11 Pandas 数据框内部操作
11.1 引言数据框操作的数据清洗价值
数据清洗(Data Cleaning)是数据分析中最耗时的环节,通常占据60-80%的时间。Pandas提供了丰富的数据框内部操作方法,使得数据清洗工作变得高效而可靠。
理论背景:数据质量原则
高质量数据分析的前提是高质量数据。数据清洗的目标: 1. 完整性: 无缺失值或合理处理 2. 一致性: 格式统一,单位一致 3. 准确性: 值在合理范围内 4. 唯一性: 无重复记录
11.2 数据读取与基础操作
11.2.1 read_csv/read_excel参数详解
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import pandas as pd # 导入Pandas数据分析库
#将第一列(date)设置为索引,只读取指定的列usecols
df=pd.read_csv("https://huoran.oss-cn-shenzhen.aliyuncs.com/20230306/csv/1632645776084066304.csv",index_col=0,usecols=['date','syzg','zgpa','zgjz']).dropna()
Trade_days=df.shape[0] # 获取数据维度信息
print(f'2022年共有{Trade_days}个交易日') # 输出2022年共有
stock_price=df.loc['2022-03-01','zgjz'] # 按标签索引提取数据
print(f'3月第一个交易日中国建筑价格为{stock_price}元') # 输出3月第一个交易日中国建筑价格为
df_asc=df.sort_index(ascending=True) # 按索引排序
print(df_asc.head(8)) # 输出前几行数据代码深度解析:
index_col的作用:
- 将某列设为行索引(通常是日期)
- 便于时间序列分析
- 减少内存占用(索引不重复存储)
usecols的优势:
- 内存效率: 只加载需要的列
- 读取速度: 减少I/O操作
- 代码清晰: 明确分析目标
链式操作:
df = (pd.read_csv(...) .dropna() .sort_index())
11.2.2 数据框基础属性
# =============================================================================
# 题目:查看DataFrame的基本属性和结构信息
# =============================================================================
# 本代码块演示如何快速了解DataFrame的基本情况。
# 金融应用场景:数据探索性分析(EDA),检查数据质量,确认数据覆盖范围。
# =============================================================================
# ==================== 数据框形状 ====================
print(f"数据框形状: {df.shape}") # 返回元组(行数, 列数)
print(f" - 行数(交易日): {df.shape[0]}") # 交易日数量
print(f" - 列数(股票): {df.shape[1]}") # 股票数量
# ==================== 交易日数量 ====================
Trade_days = df.shape[0] # 保存交易日数量到变量
print(f"\n2022年共有{Trade_days}个交易日") # 显示交易日统计
# ==================== 索引信息 ====================
print(f"\n索引类型: {type(df.index)}") # 显示索引类型(DatetimeIndex)
print(f"索引范围: {df.index.min()} 到 {df.index.max()}") # 显示日期范围
# 输出解释:显示数据涵盖的起始日期和结束日期
# ==================== 列名 ====================
print(f"\n列名(股票代码):")
print(df.columns.tolist()) # 将列名转换为列表显示
# 输出解释:syzg(三一重工)、zgpa(中国平安)、zgjz(中国建筑)
# ==================== 数据类型 ====================
print(f"\n数据类型:")
print(df.dtypes) # 显示每列的数据类型
# 输出解释:所有列都是float64类型,表示价格数据
# ==================== 内存使用 ====================
print(f"\n内存使用:")
print(df.memory_usage(deep=True)) # 显示每列的内存占用
# 输出解释:deep=True深入计算字符串等对象的内存使用11.3 数据选择与索引
11.3.1 loc基于标签的索引
loc使用标签(行/列名)进行选择,包含末端。
# =============================================================================
# 题目:使用loc基于标签选择数据
# =============================================================================
# 本代码块演示如何使用loc方法根据标签(日期、列名)选择数据。
# 金融应用场景:查询特定日期的股价,提取特定日期范围的数据,条件筛选。
# =============================================================================
# ==================== 获取特定日期的单个值 ====================
stock_price = df.loc['2022-03-01', 'zgjz'] # 使用loc选择特定行和列的交叉点
print(f"3月第一个交易日中国建筑价格: {stock_price}元")
# 输出解释:显示2022-03-01这一天zgjz(中国建筑)的收盘价
# ==================== 选择多行多列(切片) ====================
subset = df.loc[ # 使用loc选择数据子集
'2022-03-01':'2022-03-05', # 行切片:日期范围(包含两端)
['syzg', 'zgpa'] # 列选择:指定列名列表
]
print(f"\n3月1-5日,三一重工和中国平安的价格:")
print(subset)
# 输出解释:显示3月1日至5日(共5行),syzg和zgpa两列的数据
# 注意:loc的标签切片包含两端(与Python切片不同)
# ==================== 布尔条件(条件筛选) ====================
print(f"\n三一重工价格>20的交易日:")
syzg_high = df.loc[df.syzg > 20] # 使用布尔条件选择行
print(syzg_high)
# 输出解释:显示所有syzg列价格大于20的行
# df.syzg > 20返回布尔Series,loc用它来筛选行11.3.2 iloc基于位置的索引
iloc使用整数位置进行选择,不包含末端。
# =============================================================================
# 题目:使用iloc基于整数位置选择数据
# =============================================================================
# 本代码块演示如何使用iloc方法根据整数位置选择数据。
# 金融应用场景:获取前N行数据,跳过表头,随机采样,批量处理。
# =============================================================================
# ==================== 前5行前2列 ====================
print("前5行前2列:")
print(df.iloc[:5, :2]) # 行位置0-4,列位置0-1
# 输出解释:显示前5个交易日,前2列股票的价格
# 注意:iloc的切片不包含末端(标准Python切片规则)
# ==================== 特定位置的单个值 ====================
print(f"\n第1行第1列: {df.iloc[0, 0]}") # 第1行(位置0),第1列(位置0)
# 输出解释:显示第1个交易日,第1列股票的价格
# ==================== 负索引(倒数) ====================
print(f"\n倒数第3行:")
print(df.iloc[-3]) # 倒数第3行(所有列)
# 输出解释:显示倒数第3个交易日的所有股票价格
# 负数从末尾开始计数:-1是最后1行,-2是倒数第2行11.4 数据排序
11.4.1 sort_index按索引排序
# =============================================================================
# 题目:按索引(日期)排序DataFrame
# =============================================================================
# 本代码块演示如何按行索引排序数据。
# 金融应用场景:确保时间序列数据按时间顺序排列,这是时间序列分析的前提。
# =============================================================================
# ==================== 升序排序(默认) ====================
df_asc = df.sort_index(ascending=True) # 按索引升序排序(早到晚)
print("升序排序(默认):")
print(df_asc.head(8)) # 显示前8行
# 输出解释:数据按日期从早到晚排列(2022-01-04在最前)
# ==================== 降序排序 ====================
df_desc = df.sort_index(ascending=False) # 按索引降序排序(晚到早)
print(f"\n降序排序:")
print(df_desc.head(3)) # 显示前3行(实际是最晚的3天)
# 输出解释:数据按日期从晚到早排列(最新的日期在最前)金融应用: 确保时间序列数据按时间顺序排列
11.4.2 sort_values按值排序
# =============================================================================
# 题目:按列值排序DataFrame
# =============================================================================
# 本代码块演示如何按某列或多列的值排序。
# 金融应用场景:找出股价最高/最低的交易日,多维度排序分析。
# =============================================================================
# ==================== 按单列排序 ====================
print("按三一重工价格降序:")
df_sorted = df.sort_values('syzg', ascending=False) # 按syzg列降序排序
print(df_sorted.head()) # 显示前几行
# 输出解释:syzg价格最高的交易日排在最前面
# ==================== 按多列排序 ====================
print(f"\n先按syzg升序,再按zgpa降序:")
df_multi_sort = df.sort_values( # 按多列排序
['syzg', 'zgpa'], # 排序依据的列
ascending=[True, False] # 分别指定排序方向
)
print(df_multi_sort.head())
# 输出解释:
# - 先按syzg升序(低到高)
# - syzg相同时,按zgpa降序(高到低)
# - 适用于多层级排序需求11.5 数据筛选与查询
11.5.1 条件筛选
# =============================================================================
# 题目:使用条件表达式筛选DataFrame数据
# =============================================================================
# 本代码块演示如何使用单个或多个条件筛选数据。
# 金融应用场景:找出股价突破关键点的交易日,多指标联合筛选。
# =============================================================================
# ==================== 单条件筛选 ====================
print("三一重工>20:")
print(df[df.syzg > 20].head()) # 使用布尔条件筛选
# 输出解释:显示syzg>20的所有行(前几行)
# df.syzg > 20返回布尔Series,用于筛选行
# ==================== 多条件(and) ====================
print(f"\n三一重工>20 且 中国平安>40:")
print(df[(df.syzg > 20) & (df.zgpa > 40)].head())
# 输出解释:显示同时满足两个条件的行
# &表示逻辑与(AND),两边条件必须同时满足
# 注意:每个条件必须用括号括起来
# ==================== 多条件(or) ====================
print(f"\n三一重工>30 或 中国平安>45:")
print(df[(df.syzg > 30) | (df.zgpa > 45)].head())
# 输出解释:显示满足至少一个条件的行
# |表示逻辑或(OR),两边条件满足一个即可
# ==================== 使用isin方法(成员检查) ====================
print(f"\n特定日期的数据:")
dates_to_check = ['2022-03-01', '2022-03-02', '2022-03-03'] # 日期列表
print(df.loc[dates_to_check]) # 选择索引在列表中的行
# 输出解释:显示这3个特定日期的数据
# 等价于df[df.index.isin(dates_to_check)]11.5.2 query方法
query方法提供了更直观的查询语法:
# =============================================================================
# 题目:使用query方法进行更直观的数据查询
# =============================================================================
# 本代码块演示query方法,它提供了类似SQL的查询语法。
# 金融应用场景:编写复杂的多条件查询,提高代码可读性。
# =============================================================================
# ==================== 简单条件 ====================
result1 = df.query('syzg > 20') # 使用query方法筛选
print("syzg > 20:")
print(result1.head())
# 输出解释:与df[df.syzg > 20]结果相同
# 优势:语法更直观,不需要重复写df前缀
# ==================== 多条件 ====================
result2 = df.query('syzg > 20 and zgpa < 40') # 多条件查询
print(f"\nsyzg > 20 and zgpa < 40:")
print(result2.head())
# 输出解释:显示同时满足两个条件的行
# 优势:使用and/or/not代替&/|/~,更符合自然语言
# ==================== 引用变量 ====================
threshold = 25 # 定义阈值变量
result3 = df.query('syzg > @threshold') # 使用@引用外部变量
print(f"\nsyzg > {threshold}:")
print(result3.head())
# 输出解释:显示syzg > 25的行
# @符号告诉query在Python环境中查找变量,而不是列名11.6 数据变换
11.6.1 apply与map
# =============================================================================
# 题目:使用apply和map方法进行数据变换
# =============================================================================
# 本代码块演示如何对DataFrame和Series应用自定义函数。
# 金融应用场景:计算价格区间、分类评级、应用复杂业务逻辑。
# =============================================================================
# ==================== apply:对行或列应用函数 ====================
print("每列的极差:")
print(df.apply(lambda x: x.max() - x.min())) # 对每列应用lambda函数
# 输出解释:显示每列的最大值与最小值之差(价格波动范围)
# apply默认对列操作(axis=0)
print(f"\n每行的均值:")
print(df.apply(lambda x: x.mean(), axis=1).head()) # 对每行应用函数
# 输出解释:显示每个交易日3只股票的平均价格
# axis=1表示沿行方向操作(跨列)
# ==================== map:对Series的每个元素应用函数 ====================
print(f"\n将价格分类:")
# ------------------- 定义分类函数 -------------------
def categorize_price(price): # 定义价格分类函数
"""
根据价格将股票分类为高、中、低三档
参数:
price: 股票价格
返回:
'高'/'中'/'低': 价格等级
"""
if price > 30: # 价格大于30
return '高' # 高价股
elif price > 20: # 价格在20-30之间
return '中' # 中价股
else: # 价格小于等于20
return '低' # 低价股
# ------------------- 应用分类函数 -------------------
syzg_category = df['syzg'].map(categorize_price) # 对syzg列的每个元素应用函数
print(syzg_category.head(10)) # 显示前10个分类结果
# 输出解释:每个价格被转换为'高'/'中'/'低'三类之一
# map只用于Series,对每个元素逐个应用函数